using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Globalization;


namespace PocketLibrary.Blog
{
    public class Atom : IBlog
    {

        public bool MultiBlogsSupported { get { return false; } }
        public ServiceType ServiceType
        {
            get { return ServiceType.Blogging; }
        }

        public int BlogId
        {
            get { return iblogid; }
            set { iblogid = value; }
        }
        public string BlogName
        {
            get { return sblogname; }
            set { sblogname = value; }
        }

        /// <summary>
        /// url for blog. eg. http://www.foo.bar/blog/
        /// </summary>
        public string BlogUrl
        {
            get { return sblogurl; }
            set { sblogurl = value; }
        }

        /// <summary>
        /// url for blog api implementation. eg. http://www.foo.bar/api/
        /// </summary>
        public string ApiUrl
        {
            get { return sapiurl; }
            set { sapiurl = value; }
        }

        public string UserName
        {
            get { return susername; }
            set { susername = value; }
        }
        public string PassWord
        {
            get { return spassword; }
            set { spassword = value; }
        }

        int iblogid;
        string sblogname = "";
        string sblogurl = "";
        string sapiurl = "";
        string susername = "";
        string spassword = "";
        protected XmlDocument rcvXmlDoc = new XmlDocument();

        public string ServiceFeed = "";
        public string ServicePost = "";
        public string Alternate = "";
        public BlogType Type
        {
            get { return BlogType.Blogger; }
        }

        public event RequestProgressHandler OnRequestProgress;

        void ReqProgress(int pro)
        {
            if (OnRequestProgress != null)
            {
                OnRequestProgress(new RequestProgressArgs(pro));
            }
        }

        public HelperBlogs[] UserBlogs
        {
            get
            {
                return iuserblogs;
            }
            set
            {
                iuserblogs = value;
            }
        }

        HelperBlogs[] iuserblogs;

        public Atom()
        {
        }

        public void getUserBlogs()
        {
            try
            {
                HttpWebRequest request = CreateRequest(ApiUrl);
                request.Method = "GET";

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                string xmlData = ReadResponseBody(response);

                rcvXmlDoc.LoadXml(xmlData);

                XmlNodeList links = rcvXmlDoc.GetElementsByTagName("link");

                HelperBlogs[] userBlogs = new HelperBlogs[(int)links.Count / 3];

                for (int i = 0; i < userBlogs.Length; i++)
                {
                    HelperBlogs temp = new HelperBlogs();
                    temp.ServicePost = ((XmlNode)links[i * 3 + 0]).Attributes["href"].Value.ToString();
                    temp.ServiceFeed = ((XmlNode)links[i * 3 + 1]).Attributes["href"].Value.ToString();
                    temp.blogUrl = ((XmlNode)links[i * 3 + 2]).Attributes["href"].Value.ToString();
                    temp.blogName = ((XmlNode)links[i * 3 + 2]).Attributes["title"].Value.ToString();
                    userBlogs[i] = temp;
                }
                iuserblogs = userBlogs;

            }
            catch (WebException ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.InnerException.Message);
            }
        }

        public void SelectBlog(HelperBlogs selection)
        {
            HelperBlogs inner = selection;
            this.Alternate = inner.Alternate;
            this.ServiceFeed = inner.ServiceFeed;
            this.ServicePost = inner.ServicePost;
            this.BlogName = inner.blogName;
            this.BlogUrl = inner.blogUrl;
        }

        public BlogPost[] getRecentPosts(int numPosts)
        {
            HttpWebRequest request = CreateRequest(ServiceFeed);
            request.Method = "GET";

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            string xmlData = ReadResponseBody(response);

            rcvXmlDoc.LoadXml(xmlData);

            XmlNodeList posts = rcvXmlDoc.GetElementsByTagName("entry");

            BlogPost[] posted = new BlogPost[posts.Count];

            for (int i = 0; i < posts.Count; i++)
            {
                BlogPost atompost = new BlogPost();
                atompost.ServiceEdit = posts[i].ChildNodes[0].Attributes[0].Value; // 0
                atompost.postTitle = posts[i].ChildNodes[0].Attributes[2].Value;
                atompost.postBody = posts[i].ChildNodes[8].InnerText;
                atompost.publish = posts[i].ChildNodes[9].InnerText;
                if (atompost.publish == "true")
                    atompost.publish = "false";
                else atompost.publish = "true";
                posted[i] = atompost;
            }
            return posted;
        }

        public BlogPost getPost(string postid)
        {
            return new BlogPost();
        }

        public string newPost(string title, string post, string publish)
        {
            HttpWebRequest request = CreateRequest(ServicePost);

            request.Method = "POST";
            request.ContentType = "application/xml";

            // HACK flip true -> false
            if (publish == "true")
                publish = "false";
            else
                publish = "true";

            StringBuilder sb = new StringBuilder();
            sb.Append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
            sb.Append("<entry version=\"0.3\" xmlns=\"http://purl.org/atom/ns#\">");
            sb.Append("<title mode=\"escaped\" type=\"text/html\">" + title + "</title>");
            sb.Append("<issued>" +
                DateTime.UtcNow.ToString("u", CultureInfo.InvariantCulture).Replace(' ', 'T')
                + "</issued>");
            sb.Append("<generator url=\"http://www.choomba.org\">TaskuBlogi 1.0</generator>");
            sb.Append("<content type=\"text/html\">"); // application/xhtml+xml
            sb.Append("<div xmlns=\"http://www.w3.org/1999/xhtml\">" + post + "</div>");
            sb.Append("</content>");
            sb.Append("<draft xmlns=\"http://purl.org/atom-blog/ns#\">" + publish + "</draft>"); // is this post a draft
            sb.Append("</entry>");
            WriteRequestBody(request, sb.ToString());
            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                response = (HttpWebResponse)ex.Response;

                //return "General failure";
            }
            finally
            {
                if (response.StatusCode == HttpStatusCode.OK)
                    ReadResponseBody(response);
                response.Close();

            }
            return response.StatusCode.ToString();
        }

        public string editPost(BlogPost edit)
        {
            HttpWebRequest request = CreateRequest(edit.ServiceEdit);
            request.Method = "PUT";
            request.ContentType = "application/xml";
            // HACK flip true -> false
            if (edit.publish == "true")
                edit.publish = "false";
            else
                edit.publish = "true";


            StringBuilder sb = new StringBuilder();
            sb.Append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
            sb.Append("<entry version=\"0.3\" xmlns=\"http://purl.org/atom/ns#\">");
            sb.Append("<title mode=\"escaped\" type=\"text/html\">" + edit.postTitle + "</title>");
            sb.Append("<issued>" +
                DateTime.UtcNow.ToString("u", CultureInfo.InvariantCulture).Replace(' ', 'T')
                + "</issued>");
            sb.Append("<generator url=\"http://www.choomba.org\">TaskuBlogi 1.0</generator>");
            sb.Append("<content type=\"text/html\">"); // application/xhtml+xml
            sb.Append("<div xmlns=\"http://www.w3.org/1999/xhtml\">" + edit.postBody + "</div>");
            sb.Append("</content>");
            sb.Append("<draft xmlns=\"http://purl.org/atom-blog/ns#\">" + edit.publish + "</draft>"); // is this post a draft
            sb.Append("</entry>");
            WriteRequestBody(request, sb.ToString());
            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                response = (HttpWebResponse)ex.Response;

                //return "General failure";
            }
            finally
            {
                if (response.StatusCode == HttpStatusCode.OK)
                    ReadResponseBody(response);
                response.Close();

            }
            return response.StatusCode.ToString();
        }

        public Category getPostCategory(string postid)
        {
            throw new Exception("Not supported");
        }

        public string newMediaObject(string tiedostonimi, string tiedosto)
        {
            throw new Exception("Not supported");
        }

        public void setPostCategory(string postid, Category cat)
        {
            throw new Exception("Not supported");
        }

        public void getBlogCategories()
        {
            throw new Exception("Not supported");
        }

        public string newMediaObject(string tiedostonimi, string tiedosto, Stream contents)
        {
            throw new Exception("Not supported");
        }

        #region Http Helper Methods

        private HttpWebRequest CreateRequest(string uri)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
            request.PreAuthenticate = true;
            request.ProtocolVersion = new Version("1.1");
            request.SendChunked = false;
            request.UserAgent = "TaskuBlogi 1.0";
            //request.Credentials = new NetworkCredential(UserName, PassWord);

            byte[] _basic = Encoding.ASCII.GetBytes(UserName + ":" + PassWord);
            string _strbasic = Convert.ToBase64String(_basic);
            request.Headers.Add("Authorization: Basic " + _strbasic);

            return request;
        }

        private void GenerateXWSSEHeader(WebRequest webreq, string username, string password)
        {
            string Nonce = new Random().Next().ToString(CultureInfo.InvariantCulture);
            string Created = DateTime.UtcNow.ToString("u", CultureInfo.InvariantCulture).Replace(' ', 'T');

            // Fill in the password
            SHA1 md = new SHA1CryptoServiceProvider();
            string v = Nonce + Created + password;
            byte[] digest = md.ComputeHash(Encoding.Default.GetBytes(v));
            string Password64 = Convert.ToBase64String(digest);

            webreq.Headers.Add("X-WSSE", "UsernameToken Username=\"" +
                username + "\", " +
                "PasswordDigest=\"" +
                Password64 + "\", " +
                "Nonce=\"" +
                Convert.ToBase64String(Encoding.Default.GetBytes(Nonce)) + "\", " +
                "Created=\"" +
                Created + "\"");
        }

        private string ReadResponseBody(HttpWebResponse response)
        {
            string body;

            Stream stream = response.GetResponseStream();

            StreamReader reader = new StreamReader(stream, Encoding.UTF8);

            body = reader.ReadToEnd();

            stream.Close();

            return body;
        }

        private void WriteRequestBody(HttpWebRequest request, string body)
        {
            byte[] bytes;

            bytes = Encoding.UTF8.GetBytes(body);

            request.ContentLength = bytes.Length;

            Stream stream = request.GetRequestStream();

            stream.Write(bytes, 0, bytes.Length);

            stream.Close();
        }

        #endregion

        public override string ToString()
        {
            return BlogName;
        }
    }
}
